/**
 * author      : dormi330
 * date        : 2018/6/26
 * project     : mybatis
 * description : 应用层服务
 */

package com.deep.trade.application.order;

import com.deep.trade.adaptor.required.IdService;
import com.deep.trade.adaptor.required.MemberAddress;
import com.deep.trade.adaptor.required.inventory.DtoAssureInventory;
import com.deep.trade.adaptor.required.inventory.InventoryService;
import com.deep.trade.adaptor.required.member.Member;
import com.deep.trade.adaptor.required.member.MemberService;
import com.deep.trade.common.CommonUtils;
import com.deep.trade.common.TradeException;
import com.deep.trade.domain.order.CommandPlaceOrder;
import com.deep.trade.domain.order.OrderSummary;
import com.deep.trade.order.dto.InDtoPlaceOrder;
import com.deep.trade.order.dto.OutDtoCalculatePayment;
import com.deep.trade.order.dto.SkuAndQty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PlaceOrderService {

    @Autowired
    private IdService idService;

    @Autowired
    private MemberService memberService;

    @Autowired
    private CommandPlaceOrder commandPlaceOrder;

    @Autowired
    private InventoryService inventoryService;

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    /**
     * 新建订单
     *
     * @param inDtoPlaceOrder 创建订单的入参
     * @return 订单创建成功与否
     * @throws Exception
     */
    public String placeOrder(InDtoPlaceOrder inDtoPlaceOrder) throws Exception {
        logger.info("{}, {}", CommonUtils.currentClassAndMethod(), inDtoPlaceOrder);
        if (inDtoPlaceOrder == null) throw new TradeException("input arguments cannot be null");

        Member member = memberService.memberOfToken();
        if (null == member) throw new TradeException("cannot find member");

        // 确保库存足量
        DtoAssureInventory dtoAssureInventory = new DtoAssureInventory();
        dtoAssureInventory.setReqId(idService.uuid());
        for (SkuAndQty skuAndQty : inDtoPlaceOrder.getSkuAndQtyList()) {
            dtoAssureInventory.addItem(skuAndQty.getSkuId(), skuAndQty.getQuantity());
        }
        boolean inventoryOk = inventoryService.subInventory(dtoAssureInventory);
        if (!inventoryOk) {
            inventoryService.addInventory(dtoAssureInventory);
            throw new TradeException("inventory not fulfil");
        }

        MemberAddress address = assureMemberAddress(member.getId(), inDtoPlaceOrder.getAddressId());
        if (null == address) throw new TradeException("member address not exists");

        try {
            return commandPlaceOrder.placeOrder(member, address, inDtoPlaceOrder.getRemark(), inDtoPlaceOrder.getSkuAndQtyList(), inDtoPlaceOrder.isAudit());
        } catch (Exception ex) {
            logger.error("下单失败");
            ex.printStackTrace();
            throw new TradeException("fail to place order");
        }
    }

    /**
     * 下单之前的价格计算, 相当于 订单报价, 此时尚未下单
     *
     * @param inDtoPlaceOrder 参数
     * @throws Exception
     */
    public OutDtoCalculatePayment calculatePayment(InDtoPlaceOrder inDtoPlaceOrder) throws Exception {

        logger.info("{}, {}", CommonUtils.currentClassAndMethod(), inDtoPlaceOrder);
        if (inDtoPlaceOrder == null) throw new TradeException("input arguments cannot be null");

        Member member = memberService.memberOfToken();
        if (null == member) throw new TradeException("cannot find member");

        // 费用试算时, 不用考虑库存, 真实下单时进行确认
        MemberAddress address = assureMemberAddress(member.getId(), inDtoPlaceOrder.getAddressId());
        if (null == address) throw new TradeException("member address not exists");

        try {
            OrderSummary orderSummary = commandPlaceOrder.splitOrder(member, address, inDtoPlaceOrder.getRemark(), inDtoPlaceOrder.getSkuAndQtyList());
            OutDtoCalculatePayment outDtoCalculatePayment = new OutDtoCalculatePayment();
            BeanUtils.copyProperties(orderSummary, outDtoCalculatePayment);
            return outDtoCalculatePayment;
        } catch (Exception ex) {
            logger.error("计算价格失败");
            ex.printStackTrace();
            throw new TradeException("fail to place order");
        }
    }


    /**
     * 获取会员地址并确保正常
     *
     * @param memberId
     * @param addressId
     * @return
     * @throws Exception
     */
    private MemberAddress assureMemberAddress(String memberId, String addressId) throws Exception {
        MemberAddress memberAddress = memberService.addressOfMember(memberId, addressId);
        if (memberAddress == null) {
            String errMsg = String.format("no such memberAddress, memberId=%s, addressId=%s", memberId, addressId);
            throw new TradeException(errMsg);
        }
        return memberAddress;
    }
}
